`timescale 1ns / 1ps
`include "const.v"

module CP0(
    input clk,
    input reset,
    input [4:0] A1, // Read
    input [4:0] A2, // Write
    input [31:0] Din,
    input [31:0] PC,
    input [4:0] ExcCode,
    input [5:0] HWInt,
    input isBD,
    input We,
    input EXLSet,
    input EXLClr,
    output IntReq,
    output eret,
    output [31:0] EPC,
    output [31:0] Dout
    );
    //SR {16'b0, im, 8'b0, exl, ie};
    reg [5:0] im;
    reg exl, ie;
    //Cause {BD, 15'b0, ip, 3'b0, exc, 2'b0}
    reg [5:0] ip;
    reg BD;
    reg [4:0] exc;
    //EPC {epc[31:2], 2'b0};
    reg [31:0] epc;
    assign EPC = {epc[31:2], 2'b0};
    //PRId PRId;
    reg [31:0] PRId;

    assign Dout = (A1 == 12)? {16'b0, im, 8'b0, exl, ie} :
                  (A1 == 13)? {BD, 15'b0, ip, 3'b0, exc, 2'b0} :
                  (A1 == 14)? {epc[31:2], 2'b0} :
                  (A1 == 15)? PRId :
                              0;

    initial begin
        {im, exl, ie} <= 8'b11111101;
        {BD, ip, exc} <= 0;
        epc <= 0;
        PRId <= 32'h416c6578;
    end

    assign IntReq = ((~exl) & ie) && (EXLSet || (|(HWInt & im)));
    assign eret = EXLClr;

    always @(posedge clk) begin
        if(reset)begin
            {im, exl, ie} <= 8'b11111101;
            {BD, ip, exc} <= 0;
            epc <= 0;
            PRId <= 32'h416c6578;
        end
        else begin
            ip <= HWInt;
            if(((~exl) & ie) && (|(HWInt & im))) begin
                BD <= isBD;
                exc <= `Int;
                epc <= PC - (isBD << 2);
                exl <= 1;
            end
            else if(((~exl) & ie) && EXLSet) begin
                BD <= isBD;
                exc <= ExcCode;
                epc <= PC - (isBD << 2);
                exl <= 1;
            end
            else if(EXLClr)begin
                exl <= 0;
            end 
            else if(We) begin
                case(A2)
                    12:{im, exl, ie} <= {Din[15:10], Din[1], Din[0]};
                    14:epc <= Din;
                    default:;
                endcase
            end
            else ;
        end
    end
endmodule
